package netty.rpc.register;

import org.apache.curator.RetryPolicy;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.framework.recipes.cache.*;
import org.apache.curator.retry.ExponentialBackoffRetry;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.data.Stat;

import java.nio.charset.StandardCharsets;
import java.util.Collections;
import java.util.List;

/**
 * 注册中心-ZK实现
 * @author Jim
 * @version 1.0.0
 * @descripition:
 * @date 2022/5/21 19:59
 */
public class RegisterServiceZKImpl implements RegisterService{

    private CuratorFramework client;

    /**
     *
     * @param path 路径
     * @param value 值
     * @param isPersistent 是否持久化
     * @throws Exception
     */
    @Override
    public void registerPathIfNotExists(String path, String value, boolean isPersistent) throws Exception {
        Stat stat = client.checkExists().forPath(path);
        if (stat == null){
            client.create()
                    .creatingParentsIfNeeded()
                    .withMode(isPersistent?CreateMode.PERSISTENT:CreateMode.EPHEMERAL)
                    .forPath(path,value.getBytes());
        }else {
            client.setData().forPath(path, value.getBytes("UTF-8"));
        }
    }

    @Override
    public void createDirector(String path, boolean isPersistent) throws Exception {
        Stat stat = client.checkExists().forPath(path);
        if (stat == null){
            client.create()
                    .creatingParentsIfNeeded()
                    .withMode(isPersistent?CreateMode.PERSISTENT:CreateMode.EPHEMERAL)
                    .forPath(path);
        }
    }

    @Override
    public List<String> getChildrenDirectors(String path) throws Exception{
        Stat stat = client.checkExists().forPath(path);
        if (stat != null){
            return client.getChildren().forPath(path);
        }
        return Collections.EMPTY_LIST;
    }

    @Override
    public boolean registerEphemeralNode(String path, String value) throws Exception {
        try {
            client.create()
                   .withMode(CreateMode.EPHEMERAL)
                   .forPath(path,value.getBytes(StandardCharsets.UTF_8));
        } catch (Exception e) {
            throw e;
        }
        return true;
    }

    @Override
    public boolean registerEphemeralNode(String path) throws Exception {
        try {
            Stat stat = client.checkExists().forPath(path);
            if (stat == null){
                client.create()
                        .withMode(CreateMode.EPHEMERAL)
                        .forPath(path);
            }
        } catch (Exception e) {
            throw e;
        }
        return true;
    }

    @Override
    public boolean registerPersistentNode(String path, String value) throws Exception {
        return false;
    }

    @Override
    public void enableService(String serviceName) throws Exception {

    }

    @Override
    public void unableService(String serviceName) throws Exception {

    }

    @Override
    public void enableServiceInterface(String serviceName, String interfaceName) throws Exception {

    }

    @Override
    public void unableServiceInterface(String serviceName, String interfaceName) throws Exception {

    }

    @Override
    public String getServiceDefinition(String env,String serviceId) {
        try {
            return new String(client.getData().forPath(Register.PATH + "-" + env  + Register.SERVICE_PREFIX + "/" + serviceId));
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    @Override
    public List<String> getServiceInstance(String env,String serviceId) {

        try {
            return client.getChildren().forPath(Register.PATH + "-" + env + Register.INSTANCE_PREFIX + "/" + serviceId);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    @Override
    public void addWatcherListener(String path, Notify notify) throws Exception{
        PathChildrenCache cache = new PathChildrenCache(client, path, true);
        cache.getListenable().addListener(new PathChildrenCacheListener() {
            @Override
            public void childEvent(CuratorFramework client, PathChildrenCacheEvent event) throws Exception {
                switch (event.getType()){
                    case CHILD_ADDED:
                        notify.onAdd(event.getData().getPath(), new String(event.getData().getData()));
                        break;
                    case CHILD_UPDATED:
                        notify.onUpdate(event.getData().getPath(), new String(event.getData().getData()));
                        break;
                    case CHILD_REMOVED:
                        notify.onDelete(event.getData().getPath());
                        break;
                    default:
                        break;
                }
            }
        });
        cache.start();
    }

    @Override
    public void init(RegisterProperties registerProperties) throws Exception {
        RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000, 3);
        client = CuratorFrameworkFactory.newClient(registerProperties.getRegistryAddress(),
                registerProperties.getSessionTimeOut(),registerProperties.getConnectionTimeOut(), retryPolicy);
        client.start();
    }


}
